// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import React, { useEffect, useCallback } from "react";
import { useState } from "react";
import { Link } from "react-router-dom";
import "./draw.css";
import { TweenMax } from "gsap";
import { Space, Button, Modal } from "antd";
import { oneBecomesTwo } from "./Ways";
import useInterval from "./useInterval/index";

const PIXI = await import("pixi.js");

// PIXI 的扩展
PIXI.DisplayObject.prototype.set = function (arg) {
  for (const key in arg) {
    this[key] = arg[key];
  }
};

try {
  // scale 属性拍平
  Object.defineProperties(PIXI.DisplayObject.prototype, {
    scaleX: {
      set: function (value) {
        this.scale.x = value;
      },
      get: function () {
        return this.scale.x;
      },
    },
    scaleY: {
      set: function (value) {
        this.scale.y = value;
      },
      get: function () {
        return this.scale.y;
      },
    },
    pivotX: {
      set: function (value) {
        this.pivot.x = value;
      },
      get: function () {
        return this.pivot.x;
      },
    },
    pivotY: {
      set: function (value) {
        this.pivot.y = value;
      },
      get: function () {
        return this.pivot.y;
      },
    },
    anchorX: {
      set: function (value) {
        this.anchor.x = value;
      },
      get: function () {
        return this.anchor.x;
      },
    },
    anchorY: {
      set: function (value) {
        this.anchor.y = value;
      },
      get: function () {
        return this.anchor.y;
      },
    },
  });
  // eslint-disable-next-line no-empty
} catch {}

const resolution = 2; // 解析度

const index = (props) => {
  const { level, lineWidth, vertexRadius, search } = props;

  // 游戏是否解锁成功
  const [gameover, setGameover] = useState(false);
  // 游戏时间
  const [timeSeconds, setTimeSeconds] = useState(1);
  const [gameTime, setGameTime] = useState(`00 : 00`);
  // 游戏解锁成功显示对话框
  const [isModalVisible, setIsModalVisible] = useState(false);
  // 加载关卡失败
  const [failedToLoadLevel, setFailedToLoadLevel] = useState(false);

  useEffect(() => {
    gameover && setIsModalVisible(true);
  }, [gameover]);

  const handleOk = () => {
    setIsModalVisible(false);
    location.replace(`/level?index=${search + 1}`);
  };

  const handleCancel = () => {
    setIsModalVisible(false);
  };

  useInterval(() => {
    const { lines } = level;
    if (!gameover && lines?.length !== 0) {
      setTimeSeconds(timeSeconds + 1);
      const minutes = oneBecomesTwo(Math.floor(timeSeconds / 60)),
        seconds = oneBecomesTwo(Math.floor(timeSeconds % 60));
      setGameTime(`${minutes} : ${seconds}`);
    }
  }, 1000);

  const paint = useCallback(() => {
    const { lines, lineColor, activeVertexColor, vertexColor, strokeColor } =
      level;

    // 手绘的线段
    let strokes = [];
    // 已连接的线段 map
    const linesMap = new Map();
    // 已连接的线段 array
    let linesList = [];
    // 激活点集合
    let activationPointSet = [];

    // 是否有效点
    let bool = false;

    // 倍率
    const ratio = 375 / Math.min(document.body.clientWidth, 540);

    // 端点
    // eslint-disable-next-line prefer-const
    let coordinatePoints = [];
    // 当前的点
    let curVertex;
    // 解除锁定
    let lock = false;
    // 默认不可以绘制
    let canStroke = false;
    // 当前线段
    let curStroke = null;

    const app = new PIXI.Application({
      width: 375,
      height: 603,
      resolution,
      antialias: true,
      backgroundAlpha: 0,
      view: document.getElementById("easel"),
    });

    const viewLeft = document
      .querySelector("#draw")
      .getBoundingClientRect().left;

    // touchstart
    function touchstartHandle(e) {
      canStroke = true;
      lock = true;
      let { clientX: x, clientY: y } = e;
      // 修正 x
      x -= viewLeft;
      x *= ratio;
      y *= ratio;

      if (!bool || strokes.length === 0) {
        bool = check(x, y);
        // 手指下没有端点
        if (!bool) canStroke = false;
        // 手指下有端点
        else {
          // 生成新位置的激活点
          addActiveVertex(bool);
        }
      } else {
        generateStroke(x, y);
      }

      if (strokes.length === lines.length) {
        setGameover(true);
        removeActiveVertex();
        removeActiveStroke();
      }
    }

    // touchmove
    function touchmoveHandle(e) {
      if (!curVertex) return;
      // 不能画线
      if (canStroke === false || lock === false) return;
      let { clientX: x, clientY: y } = e;

      // 修正 x
      x -= viewLeft;
      x *= ratio;
      y *= ratio;

      generateStroke(x, y);
      if (strokes.length === lines.length) {
        setGameover(true);
        removeActiveVertex();
        removeActiveStroke();
      } else {
        updateChangingLine(x, y);
      }
    }

    // 创建一条长度为0的手绘线段
    function generateStroke(x0, y0) {
      if (!bool) return;
      const coord = check(x0, y0);
      if (!coord) return;
      const { x: x1, y: y1 } = bool;
      const { x: x2, y: y2 } = coord;
      for (const item of lines) {
        const { x1: itemX1, x2: itemX2, y1: itemY1, y2: itemY2 } = item;
        const lineBool =
          (itemX1 === x1 && itemY1 === y1 && itemX2 === x2 && itemY2 === y2) ||
          (itemX1 === x2 && itemY1 === y2 && itemX2 === x1 && itemY2 === y1);
        if (lineBool && !linesMap.get(item)) {
          addActiveVertex(coord);
          updateLine({ x1, y1, x2, y2 });
          linesMap.set(item, true);
          linesList.push(item);
          bool = coord;
          break;
        }
      }
    }

    function updateChangingLine(x2, y2) {
      if (!bool) return;
      removeActiveStroke();
      const { x: x1, y: y1 } = bool;
      curStroke = new PIXI.Graphics()
        .lineStyle(lineWidth, strokeColor, 1)
        .moveTo(x1, y1)
        .lineTo(x2, y2)
        .closePath();

      // 添加到舞台
      app.stage.addChild(curStroke);
      // 设置层级
      app.stage.setChildIndex(curStroke, baseLines.length);
    }

    function updateLine({ x1, y1, x2, y2 }) {
      const paintedStroke = new PIXI.Graphics()
        .lineStyle(lineWidth, strokeColor, 1)
        .moveTo(x1, y1)
        .lineTo(x2, y2)
        .closePath();

      strokes.push(paintedStroke);

      // 添加到舞台
      app.stage.addChild(paintedStroke);
      // 设置层级
      app.stage.setChildIndex(paintedStroke, baseLines.length);
    }

    // touchend
    function touchendHandle() {
      // 重置为不可绘制
      canStroke = false;
      lock = false;
      if (strokes.length === 0) {
        bool = false;
        removeActiveVertex();
      }
      removeActiveStroke();
    }

    // 描绘底图线条
    const baseLines = lines?.map(({ x1, y1, x2, y2 }) => {
      const line = new PIXI.Graphics()
        .lineStyle(lineWidth, lineColor, 1)
        .moveTo(x1 / 2, y1 / 2)
        .lineTo(x2 / 2, y2 / 2)
        .closePath();
      app.stage.addChild(line);
      return line;
    });

    // 收集当前端点
    lines.forEach((item) => {
      ["x1", "y1", "x2", "y2"].forEach(
        (key) => (item[key] = item[key] / resolution)
      );
      const { x1, y1, x2, y2 } = item;
      addCoords({ x: x1, y: y1 }, { x: x2, y: y2 });
    });

    //  向 coords 添加端点
    function addCoords(...coords: { x?: any; y: any }[]) {
      coords.forEach(({ x, y }) => {
        for (let i = 0, len = coordinatePoints.length; i < len; ++i) {
          if (coordinatePoints[i].x === x && coordinatePoints[i].y === y) {
            return false;
          }
        }
        coordinatePoints.push({ x, y });
      });
    }

    // 描绘底图端点
    const baseVertexes = coordinatePoints.map(({ x, y }) => {
      const vertex = new PIXI.Graphics()
        .beginFill(vertexColor, 1)
        .drawCircle(x, y, vertexRadius)
        .endFill();
      app.stage.addChild(vertex);
      return vertex;
    });

    // 监测手指下是否有端点
    function check(x0, y0) {
      for (let i = 0, len = coordinatePoints.length; i < len; ++i) {
        const { x, y, connected } = coordinatePoints[i];
        // 跳过已连结的端点
        if (connected === true) continue;
        const distance = Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2));

        // 点在半径内
        if (distance <= vertexRadius * 1.5) {
          return coordinatePoints[i];
        }
      }
      return false;
    }

    // 激活的点 ----- 鼠标点击时的动画或关卡过关时的动画
    function addActiveVertex(coord, isAdd = false) {
      if (!coord) return;
      if (!isAdd) {
        activationPointSet.push(coord);
      }
      removeActiveVertex();
      const vertex = new PIXI.Graphics()
        .beginFill(activeVertexColor, 1)
        .drawCircle(0, 0, vertexRadius);
      const { x, y } = coord;
      vertex.set({ x, y });
      curVertex = vertex;
      // 添加到舞台
      app.stage.addChild(vertex);
      // 添加动画
      TweenMax.to(vertex, 0.2, {
        alpha: 0.4,
        scaleX: 1.6,
        scaleY: 1.6,
        yoyo: true,
        repeat: -1,
      });
    }

    // 移除激活点
    function removeActiveVertex() {
      app.stage.removeChild(curVertex);
      TweenMax.killTweensOf(curVertex);
    }

    // 移除旧的改变线段
    function removeActiveStroke() {
      app.stage.removeChild(curStroke);
    }

    app.renderer.view.addEventListener("pointerdown", touchstartHandle);
    app.renderer.view.addEventListener("pointerup", touchendHandle);
    app.renderer.view.addEventListener("pointermove", touchmoveHandle);
    app.renderer.view.addEventListener("pointercancel", touchendHandle);

    // 重置
    function resetStep() {
      for (const k of linesList) {
        linesMap.set(k, false);
      }
      strokes.forEach((v) => {
        v?.destroy(true, true);
      });
      strokes.length = 0;
      activationPointSet.length = 0;
      linesList.length = 0;
      removeActiveVertex();
      setGameover(false);
      setTimeSeconds(0);
    }

    // 退一步
    function backOneStep() {
      const k = linesList.at(-1);
      k && linesMap.set(k, false);
      strokes.at(-1)?.destroy(true, true);
      strokes = strokes.slice(0, -1);
      removeActiveVertex();
      activationPointSet = activationPointSet.slice(0, -1);
      linesList = linesList.slice(0, -1);

      if (strokes.length !== 0) {
        bool = activationPointSet.at(-1);
        addActiveVertex(bool, true);
      } else {
        activationPointSet.length = 0;
      }
      setGameover(false);
    }

    // 提示
    function tipStep() {
      // 描绘提示线条
    }

    const reset = document.getElementById("reset");
    const back = document.getElementById("back");
    const tip = document.getElementById("tip");
    back && back.addEventListener("click", backOneStep);
    reset && reset.addEventListener("click", resetStep);
    tip && tip.addEventListener("click", tipStep);

    function removeEvents() {
      app.renderer.view.removeEventListener("pointerdown", touchstartHandle);
      app.renderer.view.removeEventListener("pointerup", touchendHandle);
      app.renderer.view.removeEventListener("pointermove", touchmoveHandle);
      app.renderer.view.removeEventListener("pointercancel", touchendHandle);
      back && back.removeEventListener("click", backOneStep);
      reset && reset.removeEventListener("click", resetStep);
      tip && tip.removeEventListener("click", tipStep);
    }

    return {
      app,
      baseLines,
      baseVertexes,
      removeEvents,
    };
  }, []);

  useEffect(() => {
    const { lines } = level;
    if (lines?.length === 0) {
      setFailedToLoadLevel(true);
      return;
    }
    const { app, baseLines, baseVertexes, removeEvents } = paint();
    return () => {
      removeEvents();
      app.stage.removeChildren();
      baseLines.forEach((v) => {
        v.destroy(true, true);
      });
      baseVertexes.forEach((v) => {
        v.destroy(true);
      });
    };
  }, []);

  return (
    <div className="wrapper">
      <Link to="/practice">
        <div className="back"></div>
      </Link>
      <div id="draw" className="draw-area">
        {failedToLoadLevel ? (
          <div className="draw-failed">加载失败了啊</div>
        ) : (
          <canvas id="easel" className="easel"></canvas>
        )}
      </div>
      <Modal
        title={
          <div style={{ fontSize: 32, textAlign: "center", color: "#f97428" }}>
            恭喜通关
          </div>
        }
        visible={isModalVisible}
        onOk={handleOk}
        onCancel={handleCancel}
        maskClosable={false}
        okText={"下一关"}
        centered={true}
        footer={
          <div
            style={{
              display: "flex",
            }}
          >
            <div style={{ flex: "4" }}>
              <Button size="large" type="primary" onClick={handleCancel}>
                取消
              </Button>
            </div>
            <div style={{ flex: "1" }}></div>
            <div style={{ flex: "4", textAlign: "left" }}>
              <Button size="large" type="primary" onClick={handleOk}>
                下一关
              </Button>
            </div>
          </div>
        }
      >
        <div className="modal-main">
          <div style={{ flex: 1 }}>
            <div></div>
            <img
              src="../../../../imgs/star.png"
              width={112}
              height={112}
              alt=""
            />
          </div>
          <div style={{ flex: 1, fontSize: 26 }}>{gameTime}</div>
        </div>
      </Modal>
      {/* 回退、重置、提示 */}
      <div className="controls">
        <Space>
          <button id="reset" className="buttons">
            重置
          </button>
          <button id="back" className="buttons">
            回退
          </button>
          {/* <button id='tip' className='buttons'>提示</button> */}
        </Space>
      </div>
      {/* 计时 */}
      <div className="timing">
        <span style={{ display: "inline-block" }}>计时&nbsp;&nbsp;</span>
        <span>{gameTime}</span>
      </div>
    </div>
  );
};

export default index;
